#ifndef __mmH__
#define __mmH__

#include "wtfeng.h"
#include "wtftypes.h"
#include "meta.h"
#include <list>
#include <stdexcept>
#include <assert.h>

#ifndef NDEBUG
#	include <algorithm>
#endif

namespace WtfEngine
{
	class						MemoryManager;
	template <class T> class	Singleton;
	template <class T> class	WeakRef;
	template <class T> class 	GcReference;
	class						GcObject;
	
	
#define GC_INTERFACE(T)\
	public:\
		typedef WtfEngine::GcReference<T>	tRef;\
		typedef WtfEngine::WeakRef<T>		tWeakRef;\
		typedef const tRef& tRefa;\
		typedef const tWeakRef& tWeakRefa;
	
#define GC_OBJECT(T, Size)\
	public:\
		virtual unsigned GcGetSize() const{ return (Size); };\
		virtual tConstString GcGetClass() const{ return #T; };\
		virtual void GcDelete() const{ delete const_cast<T*>(this); };\
		GC_INTERFACE(T)

#define GC_ADDEDSIZE(Parent, Size)		((Size) + Parent::GcGetSize())
#define GC_ADDEDSIZE_AUTO(Parent, This)	GC_ADDEDSIZE(Parent, (sizeof(This) - sizeof(Parent)))
#define	GC_AUTOSIZE(T)					GC_OBJECT(T, sizeof(T))

	/**
	 * Garbage Collected Object Interface
	 **/
	class IGcObject {
		public:
			virtual ~IGcObject() {};

			/// Increases the object's reference count
			virtual void GcReferenceObject() const = 0;
			
			/// Decreases the object's reference count
			/// @return True if object can be deleted
			virtual bool GcDereferenceObject() const = 0;
			
			/// Registers a weak reference with the object
			virtual void GcAddWeakRef(IGcObject * volatile * pRef) const = 0;
			/// Deregisters a weak reference
			virtual void GcRemoveWeakRef(IGcObject * volatile * pRef) const = 0;

			/// Returns the number of strong references to the object
			virtual unsigned long GcRefCount() const = 0;
			/// Returns the number of strong and weak references to the object
			virtual unsigned long GcTotalRefCount() const = 0;

			virtual unsigned		GcGetSize() const = 0;
			virtual tConstString	GcGetClass() const = 0;

			/// Internal delete method - should only be called by memory manager
			virtual void GcDelete() const = 0;
	};
	
	
	/**
	 * Singleton interface
	 **/
	class ISingleton: public virtual IGcObject {
	public:
		ISingleton();
		virtual ~ISingleton();
	};

	/**
	 * A singleton class, for classes which are
	 * designed to only have one instance. Examples include the Kernel
	 * or the renderer.
	 *
	 * Just call "new Class", and the Singleton class will
	 * hold the pointer. To access the instance, call
	 * Class::GetInstance() or Class::GetInstancePtr().
	 **/
	template <class T>
	class Singleton : public virtual ISingleton
	{
	protected:
		static T*	This;

	public:
		Singleton(): ISingleton() {
			if(This) throw new std::logic_error("Singleton: already exists");
			This = static_cast<T*>(this);
		};

		virtual ~Singleton() {
			This = NULL;
		};
		
		inline static T& GetInstance() {
#ifndef NCHECK
			if(This == NULL)
				throw std::logic_error("Singleton not initialized");
#endif
			return *This;
		}

		inline static T* GetInstancePtr() {
			return &GetInstance();
		}
		
		inline static bool isInitialized() {
			return This != NULL;
		};
		
		virtual void GcReferenceObject() const {};
		virtual bool GcDereferenceObject() const { return false; };

		/// TODO: handle these properly?
		virtual void GcAddWeakRef(IGcObject * volatile * pRef) const {}
		virtual void GcRemoveWeakRef(IGcObject * volatile * pRef) const {};

		virtual unsigned long GcRefCount() const { return 1; };
		virtual unsigned long GcTotalRefCount() const { return 1; };

		GC_AUTOSIZE(Singleton<T>);
	};

	/// Static initializer for Singletons, holds the pointer to the instance
	template <class T> T * Singleton<T>::This;

	
	/**
	 * Wraps and protects a GC object which is allocated on the
	 * stack. Ensures that the object is never deleted (by referencing
	 * it) and checks that the object is not referenced when it goes out
	 * of scope.
	 **/
	template <class T>
	struct LocalObject {
		T	Object;
		
		inline explicit LocalObject(const T& obj): Object(obj) {
			Object.GcReferenceObject();
		};
		inline ~LocalObject() {
			assert(Object.GcDereferenceObject());
		};
		
		// Dereferencing operators
		inline T* operator-> () {
			return &Object;
		};
		inline T& operator* () {
			return Object;
		};
		inline const T* operator-> () const {
			return &Object;
		};
		inline const T& operator* () const {
			return Object;
		};
	};
	
	
	/**
	 * The memory manager - tracks the status of objects, reclaims memory when needed.
	 **/
	class MemoryManager : public Singleton<MemoryManager>
	{
	private:
		typedef std::list<IGcObject*>	tObjectList;
		typedef std::list<ISingleton*>	tSingletonList;
		
		tObjectList		mvpObjects;
		tSingletonList	mvpSingletons;
		unsigned		mlInvocationCount;
		;
	public:
		MemoryManager();
		~MemoryManager();
		
		unsigned Reclaim(unsigned lAmount = 0);
		void DumpStatus();
		
	protected:
		inline void RegisterSingleton(ISingleton *pObj){
			mvpSingletons.push_back(pObj);
		};
		inline void DeregisterSingleton(ISingleton *pObj){
			mvpSingletons.remove(pObj);
		};
		inline void RegisterObject(IGcObject * pObj){
			mvpObjects.push_back(pObj);
		};
		inline void DeregisterObject(IGcObject * pObj){
			mvpObjects.remove(pObj);
		};
		
		friend class ISingleton;
		friend class GcObject;
	};
	
	
	/**
	 * Thrown when attempting to dereference a null reference.
	 **/
	class ExNullRef : public std::runtime_error
	{
	public:
		ExNullRef() : std::runtime_error("GC: Null object reference") {};
	};
	
	
	template <class tThis> struct GetPtr {};
	template <class T> struct GetPtr<T*> {
		inline static T* get(T* v) { return v; };
	};
	template <class T> struct GetPtr<GcReference<T> > {
		inline static T* get(const GcReference<T>& r) {
			return r.getRef();
		};
	};
	template <class T> struct GetPtr<WeakRef<T> > {
		inline static T* get(const WeakRef<T>& r) {
			return r.getRef();
		};
	};

	/**
	 * Specifies the metric used to compare two reference types. This defaults
	 * to pointer comparison.
	 **/
	template <class tThis, class tThat>
	struct GcReferenceComparatorMetric: public GetPtr<tThis> {	
	};
	

	template <class T, class tRef>
	class BasicRef {
	public:
		BasicRef() {
			Downcast()->mpObject = NULL;
		};

		/**
		 * Ptr constructor
		 **/
		template <class U>
		BasicRef(U* ref) {
			Downcast()->mpObject = NULL;
			Downcast()->Init(ref);
		};

		/**
		 * Copy constructor
		 **/
		BasicRef(const BasicRef<T, tRef>& r) {
			Downcast()->mpObject = NULL;
			Downcast()->Init(r.Downcast()->getRef());
		};

		/**
		 * Implicit cast constructor
		 **/
		template <class _tRef>
		BasicRef(const _tRef& ref) {
			Downcast()->mpObject = NULL;
			Downcast()->Init(typename Meta::Value<_tRef>::get(ref).Downcast()->getRef());
		};
		
		~BasicRef() {
			Downcast()->Destroy();
		};


		/**
		 * Assignments
		 **/
		template <class U>
		void operator= (U* p_ref) {
	 		Downcast()->Init(p_ref);
	 	};
		void operator= (const BasicRef<T, tRef>& r) {
			Downcast()->Init(r.Downcast()->getRef());
		};
		template <class U, class _tRef>
	 	void operator= (const BasicRef<U,_tRef>& r_ref) {
			Downcast()->Init(r_ref.Downcast()->getRef());
	 	};


		// Comparison operators
		template <class U>
		inline bool operator== (const U& ref) const {
			return (typename GcReferenceComparatorMetric<tRef, U>::get(*Downcast()) == typename GcReferenceComparatorMetric<U, tRef>::get(ref));
		};
		template <class U>
		inline bool operator!= (const U& ref) const {
			return (typename GcReferenceComparatorMetric<tRef, U>::get(*Downcast()) != typename GcReferenceComparatorMetric<U, tRef>::get(ref));
		};
		template <class U>
		inline bool operator< (const U& ref) const {
			return (typename GcReferenceComparatorMetric<tRef, U>::get(*Downcast()) < typename GcReferenceComparatorMetric<U, tRef>::get(ref));
		};

		// Dereferencing operators
		T* operator-> () const
		{
			Downcast()->Validate();
			return Downcast()->getRef();
		};
	 
		T& operator* () const
		{
			Downcast()->Validate();
			return *Downcast()->getRef();
		};

		bool isNull() const {
			return (Downcast()->getRef() == NULL);
		};

		void Destroy() {
			if(!Downcast()->isNull())
				Downcast()->Kill();
		};

		inline tRef * Downcast() { return static_cast<tRef*>(this); };
		inline tRef const * Downcast() const { return static_cast<tRef const*>(this); };

		/// Default implementation of validate - does nothing
		inline void Validate() const {};
	};

	template <class T, class tRef>
	class BasicWeakRef: public BasicRef<T, tRef> {
	public:
		typedef BasicRef<T, tRef> tBasicRef;

	protected:
		mutable T * volatile mpObject;
	
		// Constructor
		BasicWeakRef(): mpObject(NULL) {
		};

		/**
		 * Implicit cast constructor
		 **/
		template <class _tRef>
		BasicWeakRef(const _tRef& ref): tBasicRef(ref) {
		};

		void Init(T* const p) const
		{
			if(mpObject)
				this->Kill();

			mpObject = p;
			
			if(p)
				p->GcAddWeakRef(&CastRef());
		};
	
		void Kill() const
		{
			mpObject->GcRemoveWeakRef(&CastRef());
		};
		
		inline IGcObject * volatile& CastRef() const {
			return reinterpret_cast<IGcObject* volatile&>(const_cast<typename Meta::ValueTraits<T>::tStorage * volatile&>(mpObject));
		};

	public:
		/**
		 * Validate - throws an exception if the reference is null.
		 **/
		void Validate() const throw(ExNullRef) {
			if(isNull())
				throw new ExNullRef();
		};

		T * getRef() const {
			return mpObject;
		};

		friend class GcObject;
		friend class BasicRef<T, tRef>;
	};

	/**
	 * Weak references are 'nullable' references. They are designed to point
	 * to an object without actually referencing it.
	 **/
	template <class T>
	class WeakRef : public BasicWeakRef<T, WeakRef<T> >
	{
	public:
		typedef BasicWeakRef<T, WeakRef<T> > tBasicRef;

		// Constructor
		WeakRef(): tBasicRef() {
		};
		
		/**
		 * Copy constructor - it's important that this is overridden, as
		 * the default would cause serious memory issues!
		 **/
		WeakRef(const WeakRef<T>& ref) : tBasicRef(ref) {
		};
		
		/**
		 * Implicit cast constructor
		 **/
		template <class tRef>
		WeakRef(const tRef& ref): tBasicRef(ref) {
		};


		/**
		 * Type assignment - we need this to override the default behaviour.
		 * This may throw, in which case this reference is not modified.
		 **/
		void operator= (const WeakRef<T>& r_ref) {
			Init(&r_ref);
		};
	};

	
	
	/**
	 * Garbage Collected Managed Object.
	 *
	 * Base class for all memory managed objects.
	 * Basically call new, use my special references,
	 * and I'll do the cleaning up for you afterwards :)
	 **/
	class GcObject : public virtual IGcObject
	{
	protected:
		/// This wraps pointers to weak references to make sure the reference is
		/// invalidated when the object is deleted.
		typedef IGcObject * volatile * tWeakRefPtr;

		mutable unsigned long             mlRefCount;
		mutable std::list<tWeakRefPtr> mvpWeakRef;
		
	public:
		GcObject() : mlRefCount(0), mvpWeakRef(){
			MemoryManager::GetInstance().RegisterObject(this);
		};
		virtual ~GcObject();
		
		unsigned long GcRefCount() const {
			return mlRefCount;
		};
		unsigned long GcTotalRefCount() const {
			return mlRefCount + mvpWeakRef.size();
		};
		
		void GcReferenceObject() const;
		bool GcDereferenceObject() const;
		
		/// Associates the given weak reference with this object. The reference will
		/// be invalidated when the object is deleted.
		void GcAddWeakRef(tWeakRefPtr pRef) const;
		void GcRemoveWeakRef(tWeakRefPtr pRef) const;
		
		template <class T>
		WtfEngine::GcReference<T> mpObject() const{
			return WtfEngine::GcReference<T>(this);
		};
		
		GC_AUTOSIZE(GcObject);
	};


	/**
	 * Reference to Garbage Collected Objects
	 *
	 * This template class defines special references
	 * for any class which derives from GcObject.
	 *
	 * IMPORTANT
	 * These references should be used instead of pointers
	 * pretty much everywhere outside the kernel.
	 **/
	template <class T>
	class GcReference: public BasicRef<T, GcReference<T> >
	{
	public:
		typedef BasicRef<T, GcReference<T> > tBasicRef;

	private:
		T *	mpObject;
		
		void Init(T* const p)
		{
			if(p) {
				p->GcReferenceObject();
			};

			T* tmp = mpObject;
			mpObject = p;

			if(tmp) {
				if(tmp->GcDereferenceObject())
					tmp->GcDelete();
			};
		};

		void Kill()
		{
			T* p = mpObject;
			mpObject = NULL;
			if(p->GcDereferenceObject())
				p->GcDelete();
		};

	public:
		// Constructor
		GcReference(){
			mpObject = NULL;
		};

		/**
		 * Copy constructor - it's important that this is overridden, as
		 * the default would cause serious memory issues!
		 **/
		GcReference(const GcReference<T>& ref) : tBasicRef(ref) {
		};
		
		/**
		 * Implicit cast constructor
		 **/
		template <class U>
		GcReference(U* ref): tBasicRef(ref) {
		};
		template <class tRef>
		GcReference(const tRef& ref): tBasicRef(ref) {
		};

		~GcReference(){
			Destroy();
		};

		/**
		 * Type assignment - we need this to override the default behaviour.
		 **/
		void operator= (const GcReference<T>& r_ref) {
			this->Init(r_ref.getRef());
		};
	 
		T*	getRef() const {
			return mpObject;
		};

		inline void Validate() const {
			assert(mpObject != NULL);
		};

		friend class BasicRef<T, GcReference<T> >;
	};
};

namespace Meta {

	/// Traits for reference types
	template <class T>
	struct ClassTraits<WtfEngine::GcReference<T> > {
		typedef WtfEngine::GcReference<T> tPtr;
		typedef T tClass;
	};
	template <class T>
	struct ClassTraits<WtfEngine::WeakRef<T> > {
		typedef WtfEngine::WeakRef<T> tPtr;
		typedef T tClass;
	};
};

#endif
